package com.mxchip.livestarmobile.mobile.util.widget.opengl;

import android.content.Context;
import android.util.AttributeSet;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;


import java.lang.ref.WeakReference;

import javax.microedition.khronos.egl.EGLContext;

public abstract class HxbEGLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {


    public HxbEGLSurfaceView(Context context) {
        super(context);
    }

    public HxbEGLSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public HxbEGLSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        getHolder().addCallback(this);
    }

    public void setSurface(Surface surface) {
        this.surface = surface;
    }

    public void setEglContext(EGLContext eglContext) {
        this.eglContext = eglContext;
    }

    public void setRender(GLRender render) {
        this.wlglRender = render;
    }

    public void setRenderMode(int renderMode) {
        if (wlglRender == null) {
            throw new RuntimeException("mast set Render before");
        }
        this.mRenderMode = renderMode;
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

        if (surface == null) {
            surface = holder.getSurface();
        }

        wleglThread = new WLEGLThread(new WeakReference<HxbEGLSurfaceView>(this));
        wleglThread.isCreate = true;
        wleglThread.start();
    }

    public EGLContext getEglContext() {
        if (wleglThread != null) {
            return wleglThread.getEglContext();
        }
        return null;
    }

    public void requestRender() {
        if (wleglThread != null) {
            wleglThread.requestRender();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        wleglThread.isChange = true;
        wleglThread.width = width;
        wleglThread.height = height;
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        wleglThread.onDestroy();
        wleglThread = null;
        surface = null;
        eglContext = null;
    }


    public interface GLRender {
        void onSurfaceCreated();

        void onSurfaceChanged(int width, int height);

        void onDrawFrame();
    }

    static class WLEGLThread extends Thread {

        public WLEGLThread(WeakReference<HxbEGLSurfaceView> wlglSurfaceViewWeakReference) {
            this.wlglSurfaceViewWeakReference = wlglSurfaceViewWeakReference;
        }

        @Override
        public void run() {
            super.run();
            isExit = false;
            isStart = false;
            object = new Object();
            eglHelper = new EglHelper();
            eglHelper.initEgl(wlglSurfaceViewWeakReference.get().surface, wlglSurfaceViewWeakReference.get().eglContext);
            while (true) {
                if (isExit) {
                    release();
                    break;
                }


                if (isStart) {
                    if (wlglSurfaceViewWeakReference.get().mRenderMode == RENDERMODE_WHEN_DIRTY) {
                        synchronized (object) {
                            try {
                                object.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    } else if (wlglSurfaceViewWeakReference.get().mRenderMode == RENDERMODE_CONTINUOUSLY) {
                        try {
                            Thread.sleep(1000 / 60);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        throw new RuntimeException("mRenderMode is Wrong value");
                    }
                }

                onCreate();

                onChange(width, height);

                onDraw();


                isStart = true;
            }
        }

        private void onCreate() {
            if (isCreate && wlglSurfaceViewWeakReference.get().wlglRender != null) {
                isCreate = false;
                wlglSurfaceViewWeakReference.get().wlglRender.onSurfaceCreated();
            }
        }

        private void onChange(int width, int height) {
            if (isChange && wlglSurfaceViewWeakReference.get().wlglRender != null) {
                isChange = false;
                wlglSurfaceViewWeakReference.get().wlglRender.onSurfaceChanged(width, height);
            }
        }

        private void onDraw() {
            if (wlglSurfaceViewWeakReference.get().wlglRender != null && eglHelper != null) {
                wlglSurfaceViewWeakReference.get().wlglRender.onDrawFrame();
                if (!isStart) {
                    wlglSurfaceViewWeakReference.get().wlglRender.onDrawFrame();
                }

                eglHelper.swapBuffers();
            }
        }

        private void requestRender() {

            if (object != null) {
                synchronized (object) {
                    object.notifyAll();
                }
            }
        }

        public void onDestroy() {

            isExit = true;
            requestRender();
        }

        public void release() {

            if (eglHelper != null) {
                eglHelper.destroyEgl();
                eglHelper = null;
                object = null;
                wlglSurfaceViewWeakReference = null;
            }

        }

        public EGLContext getEglContext() {
            if (eglHelper != null) {
                return eglHelper.getmEglContext();
            }
            return null;
        }

        private boolean isCreate = false;
        private WeakReference<HxbEGLSurfaceView> wlglSurfaceViewWeakReference;
        private EglHelper eglHelper;
        private Object object;

        private boolean isExit = true;
        private boolean isChange = false;
        private int width;
        private int height;
        private boolean isStart;
    }


    private Surface surface = null;
    private EGLContext eglContext;
    private WLEGLThread wleglThread;
    private GLRender wlglRender;

    public final static int RENDERMODE_WHEN_DIRTY = 0;
    public final static int RENDERMODE_CONTINUOUSLY = 1;
    private int mRenderMode = RENDERMODE_CONTINUOUSLY;
}
